/**
 * 数据库备份服务
 * Database Backup Service
 */

const fs = require('fs').promises;
const path = require('path');
const { spawn } = require('child_process');
const config = require('../config/config');
const logger = require('../utils/logger');

class BackupService {
  constructor() {
    this.backupPath = config.backup.path;
    this.retentionDays = config.backup.retentionDays;
    this.dbConfig = config.database;
  }

  /**
   * 初始化备份目录
   * Initialize backup directory
   */
  async initBackupDirectory() {
    try {
      await fs.mkdir(this.backupPath, { recursive: true });
      await fs.mkdir(path.join(this.backupPath, 'mysql'), { recursive: true });
      await fs.mkdir(path.join(this.backupPath, 'files'), { recursive: true });
      logger.info('Backup directories initialized successfully');
    } catch (error) {
      logger.error('Failed to initialize backup directories:', error);
      throw error;
    }
  }

  /**
   * 创建数据库备份
   * Create database backup
   */
  async createDatabaseBackup() {
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
    const backupFileName = `backup_${timestamp}.sql`;
    const backupFilePath = path.join(this.backupPath, 'mysql', backupFileName);

    try {
      logger.info('Starting database backup...');
      
      // 构建mysqldump命令
      const mysqldumpArgs = [
        '-h', this.dbConfig.host,
        '-P', this.dbConfig.port.toString(),
        '-u', this.dbConfig.user,
        '--single-transaction',
        '--routines',
        '--triggers',
        '--events',
        '--hex-blob',
        '--default-character-set=utf8mb4',
        '--result-file=' + backupFilePath,
        this.dbConfig.database
      ];

      // 如果有密码，添加密码参数
      if (this.dbConfig.password) {
        mysqldumpArgs.splice(4, 0, '-p' + this.dbConfig.password);
      }

      // 执行备份命令
      await this.executeCommand('mysqldump', mysqldumpArgs);

      // 验证备份文件
      const stats = await fs.stat(backupFilePath);
      if (stats.size === 0) {
        throw new Error('Backup file is empty');
      }

      logger.info(`Database backup created successfully: ${backupFileName} (${this.formatFileSize(stats.size)})`);
      
      return {
        success: true,
        fileName: backupFileName,
        filePath: backupFilePath,
        size: stats.size,
        timestamp: new Date()
      };
    } catch (error) {
      logger.error('Database backup failed:', error);
      
      // 清理失败的备份文件
      try {
        await fs.unlink(backupFilePath);
      } catch (cleanupError) {
        logger.error('Failed to cleanup failed backup file:', cleanupError);
      }
      
      throw error;
    }
  }

  /**
   * 执行系统命令
   * Execute system command
   */
  executeCommand(command, args) {
    return new Promise((resolve, reject) => {
      const process = spawn(command, args, {
        stdio: ['ignore', 'pipe', 'pipe']
      });

      let stdout = '';
      let stderr = '';

      process.stdout.on('data', (data) => {
        stdout += data.toString();
      });

      process.stderr.on('data', (data) => {
        stderr += data.toString();
      });

      process.on('close', (code) => {
        if (code === 0) {
          resolve(stdout);
        } else {
          reject(new Error(`Command failed with code ${code}: ${stderr}`));
        }
      });

      process.on('error', (error) => {
        reject(error);
      });
    });
  }

  /**
   * 获取备份列表
   * Get backup list
   */
  async getBackupList() {
    try {
      const mysqlBackupPath = path.join(this.backupPath, 'mysql');
      const files = await fs.readdir(mysqlBackupPath);
      
      const backups = [];
      for (const file of files) {
        if (file.endsWith('.sql')) {
          const filePath = path.join(mysqlBackupPath, file);
          const stats = await fs.stat(filePath);
          
          backups.push({
            fileName: file,
            filePath: filePath,
            size: stats.size,
            createdAt: stats.birthtime,
            modifiedAt: stats.mtime
          });
        }
      }

      // 按创建时间倒序排列
      backups.sort((a, b) => b.createdAt - a.createdAt);
      
      return backups;
    } catch (error) {
      logger.error('Failed to get backup list:', error);
      throw error;
    }
  }

  /**
   * 清理过期备份
   * Clean expired backups
   */
  async cleanExpiredBackups() {
    try {
      const backups = await this.getBackupList();
      const cutoffDate = new Date();
      cutoffDate.setDate(cutoffDate.getDate() - this.retentionDays);

      let deletedCount = 0;
      let deletedSize = 0;

      for (const backup of backups) {
        if (backup.createdAt < cutoffDate) {
          try {
            await fs.unlink(backup.filePath);
            deletedCount++;
            deletedSize += backup.size;
            logger.info(`Deleted expired backup: ${backup.fileName}`);
          } catch (error) {
            logger.error(`Failed to delete backup ${backup.fileName}:`, error);
          }
        }
      }

      if (deletedCount > 0) {
        logger.info(`Cleaned ${deletedCount} expired backups, freed ${this.formatFileSize(deletedSize)}`);
      }

      return {
        deletedCount,
        deletedSize
      };
    } catch (error) {
      logger.error('Failed to clean expired backups:', error);
      throw error;
    }
  }

  /**
   * 验证备份完整性
   * Verify backup integrity
   */
  async verifyBackupIntegrity(backupFilePath) {
    try {
      // 检查文件是否存在
      const stats = await fs.stat(backupFilePath);
      if (stats.size === 0) {
        return { valid: false, error: 'Backup file is empty' };
      }

      // 读取文件头部检查SQL格式
      const fileHandle = await fs.open(backupFilePath, 'r');
      const buffer = Buffer.alloc(1024);
      await fileHandle.read(buffer, 0, 1024, 0);
      await fileHandle.close();

      const header = buffer.toString('utf8');
      
      // 检查是否包含mysqldump标识
      if (!header.includes('-- MySQL dump') && !header.includes('-- Dump completed')) {
        return { valid: false, error: 'Invalid backup file format' };
      }

      // 检查是否包含数据库名称
      if (!header.includes(this.dbConfig.database)) {
        return { valid: false, error: 'Backup does not contain expected database' };
      }

      return { 
        valid: true, 
        size: stats.size,
        createdAt: stats.birthtime 
      };
    } catch (error) {
      return { 
        valid: false, 
        error: error.message 
      };
    }
  }

  /**
   * 获取备份统计信息
   * Get backup statistics
   */
  async getBackupStats() {
    try {
      const backups = await this.getBackupList();
      
      const stats = {
        totalBackups: backups.length,
        totalSize: backups.reduce((sum, backup) => sum + backup.size, 0),
        oldestBackup: backups.length > 0 ? backups[backups.length - 1].createdAt : null,
        newestBackup: backups.length > 0 ? backups[0].createdAt : null,
        averageSize: backups.length > 0 ? backups.reduce((sum, backup) => sum + backup.size, 0) / backups.length : 0
      };

      return stats;
    } catch (error) {
      logger.error('Failed to get backup statistics:', error);
      throw error;
    }
  }

  /**
   * 格式化文件大小
   * Format file size
   */
  formatFileSize(bytes) {
    const units = ['B', 'KB', 'MB', 'GB'];
    let size = bytes;
    let unitIndex = 0;

    while (size >= 1024 && unitIndex < units.length - 1) {
      size /= 1024;
      unitIndex++;
    }

    return `${size.toFixed(2)} ${units[unitIndex]}`;
  }

  /**
   * 恢复数据库
   * Restore database
   */
  async restoreDatabase(backupFilePath, options = {}) {
    try {
      logger.info(`Starting database restore from: ${backupFilePath}`);
      
      // 验证备份文件
      const verification = await this.verifyBackupIntegrity(backupFilePath);
      if (!verification.valid) {
        throw new Error(`Cannot restore from invalid backup: ${verification.error}`);
      }

      // 创建恢复前的备份（如果需要）
      let preRestoreBackup = null;
      if (options.createPreRestoreBackup !== false) {
        logger.info('Creating pre-restore backup...');
        preRestoreBackup = await this.createDatabaseBackup();
      }

      // 构建mysql恢复命令
      const mysqlArgs = [
        '-h', this.dbConfig.host,
        '-P', this.dbConfig.port.toString(),
        '-u', this.dbConfig.user,
        '--default-character-set=utf8mb4',
        this.dbConfig.database
      ];

      // 如果有密码，添加密码参数
      if (this.dbConfig.password) {
        mysqlArgs.splice(4, 0, '-p' + this.dbConfig.password);
      }

      // 执行恢复命令
      await this.executeRestoreCommand('mysql', mysqlArgs, backupFilePath);

      // 验证恢复结果
      const verificationResult = await this.verifyRestoreResult();

      logger.info('Database restore completed successfully');
      
      return {
        success: true,
        restoredFrom: backupFilePath,
        preRestoreBackup: preRestoreBackup,
        verification: verificationResult,
        timestamp: new Date()
      };
    } catch (error) {
      logger.error('Database restore failed:', error);
      throw error;
    }
  }

  /**
   * 执行恢复命令
   * Execute restore command
   */
  async executeRestoreCommand(command, args, inputFile) {
    const fs = require('fs').promises;
    
    return new Promise(async (resolve, reject) => {
      try {
        // 读取备份文件内容
        const backupContent = await fs.readFile(inputFile, 'utf8');
        
        const process = spawn(command, args, {
          stdio: ['pipe', 'pipe', 'pipe']
        });

        let stdout = '';
        let stderr = '';

        process.stdout.on('data', (data) => {
          stdout += data.toString();
        });

        process.stderr.on('data', (data) => {
          stderr += data.toString();
        });

        process.on('close', (code) => {
          if (code === 0) {
            resolve(stdout);
          } else {
            reject(new Error(`Restore command failed with code ${code}: ${stderr}`));
          }
        });

        process.on('error', (error) => {
          reject(error);
        });

        // 将备份内容写入mysql进程
        process.stdin.write(backupContent);
        process.stdin.end();
      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * 验证恢复结果
   * Verify restore result
   */
  async verifyRestoreResult() {
    const db = require('../database/connection');
    
    try {
      // 检查基本表是否存在
      const tables = ['users', 'notes', 'files'];
      const results = {};
      
      for (const table of tables) {
        const [rows] = await db.execute(`SELECT COUNT(*) as count FROM ${table}`);
        results[table] = rows[0].count;
      }

      // 检查数据库连接是否正常
      await db.execute('SELECT 1');
      
      return {
        valid: true,
        tableStats: results,
        timestamp: new Date()
      };
    } catch (error) {
      return {
        valid: false,
        error: error.message,
        timestamp: new Date()
      };
    }
  }

  /**
   * 获取恢复历史
   * Get restore history
   */
  async getRestoreHistory() {
    const fs = require('fs').promises;
    const path = require('path');
    
    try {
      const historyFile = path.join(this.backupPath, 'restore_history.json');
      
      try {
        const content = await fs.readFile(historyFile, 'utf8');
        return JSON.parse(content);
      } catch (error) {
        // 如果文件不存在，返回空历史
        return [];
      }
    } catch (error) {
      logger.error('Failed to get restore history:', error);
      return [];
    }
  }

  /**
   * 记录恢复历史
   * Record restore history
   */
  async recordRestoreHistory(restoreInfo) {
    const fs = require('fs').promises;
    const path = require('path');
    
    try {
      const historyFile = path.join(this.backupPath, 'restore_history.json');
      const history = await this.getRestoreHistory();
      
      history.unshift({
        ...restoreInfo,
        id: Date.now().toString(),
        timestamp: new Date().toISOString()
      });

      // 只保留最近50条记录
      const limitedHistory = history.slice(0, 50);
      
      await fs.writeFile(historyFile, JSON.stringify(limitedHistory, null, 2));
      
      logger.info('Restore history recorded');
    } catch (error) {
      logger.error('Failed to record restore history:', error);
    }
  }

  /**
   * 创建数据库结构备份（仅结构，不包含数据）
   * Create database structure backup (schema only)
   */
  async createSchemaBackup() {
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
    const backupFileName = `schema_backup_${timestamp}.sql`;
    const backupFilePath = path.join(this.backupPath, 'mysql', backupFileName);

    try {
      logger.info('Starting schema backup...');
      
      // 构建mysqldump命令（仅结构）
      const mysqldumpArgs = [
        '-h', this.dbConfig.host,
        '-P', this.dbConfig.port.toString(),
        '-u', this.dbConfig.user,
        '--single-transaction',
        '--routines',
        '--triggers',
        '--events',
        '--no-data', // 只导出结构，不导出数据
        '--default-character-set=utf8mb4',
        '--result-file=' + backupFilePath,
        this.dbConfig.database
      ];

      // 如果有密码，添加密码参数
      if (this.dbConfig.password) {
        mysqldumpArgs.splice(4, 0, '-p' + this.dbConfig.password);
      }

      // 执行备份命令
      await this.executeCommand('mysqldump', mysqldumpArgs);

      // 验证备份文件
      const stats = await fs.stat(backupFilePath);
      if (stats.size === 0) {
        throw new Error('Schema backup file is empty');
      }

      logger.info(`Schema backup created successfully: ${backupFileName}`);
      
      return {
        success: true,
        fileName: backupFileName,
        filePath: backupFilePath,
        size: stats.size,
        timestamp: new Date()
      };
    } catch (error) {
      logger.error('Schema backup failed:', error);
      
      // 清理失败的备份文件
      try {
        await fs.unlink(backupFilePath);
      } catch (cleanupError) {
        logger.error('Failed to cleanup failed schema backup file:', cleanupError);
      }
      
      throw error;
    }
  }

  /**
   * 执行完整备份流程
   * Execute complete backup process
   */
  async performBackup() {
    try {
      logger.info('Starting backup process...');
      
      // 初始化备份目录
      await this.initBackupDirectory();
      
      // 创建数据库备份
      const backupResult = await this.createDatabaseBackup();
      
      // 验证备份完整性
      const verifyResult = await this.verifyBackupIntegrity(backupResult.filePath);
      if (!verifyResult.valid) {
        throw new Error(`Backup verification failed: ${verifyResult.error}`);
      }
      
      // 清理过期备份
      const cleanupResult = await this.cleanExpiredBackups();
      
      logger.info('Backup process completed successfully');
      
      return {
        success: true,
        backup: backupResult,
        verification: verifyResult,
        cleanup: cleanupResult
      };
    } catch (error) {
      logger.error('Backup process failed:', error);
      throw error;
    }
  }

  /**
   * 执行完整恢复流程
   * Execute complete restore process
   */
  async performRestore(backupFileName, options = {}) {
    try {
      logger.info(`Starting restore process from: ${backupFileName}`);
      
      // 获取备份文件路径
      const backups = await this.getBackupList();
      const backup = backups.find(b => b.fileName === backupFileName);
      
      if (!backup) {
        throw new Error(`Backup file not found: ${backupFileName}`);
      }

      // 执行恢复
      const restoreResult = await this.restoreDatabase(backup.filePath, options);
      
      // 记录恢复历史
      await this.recordRestoreHistory({
        backupFileName: backupFileName,
        backupSize: backup.size,
        success: restoreResult.success,
        preRestoreBackup: restoreResult.preRestoreBackup?.fileName,
        verification: restoreResult.verification
      });
      
      logger.info('Restore process completed successfully');
      
      return restoreResult;
    } catch (error) {
      logger.error('Restore process failed:', error);
      
      // 记录失败的恢复历史
      await this.recordRestoreHistory({
        backupFileName: backupFileName,
        success: false,
        error: error.message
      });
      
      throw error;
    }
  }
}

module.exports = BackupService;